package marvin.webapp.rest;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.List;

import marvin.music.dto.Client;
import marvin.music.dto.ClientList;
import marvin.music.rest.ServiceURIs;
import marvin.webapp.audio.client.MarvinClient;
import marvin.webapp.audio.subscription.ClientHandler;
import marvin.webapp.audio.subscription.SubscriptionServer;
import marvin.webapp.exception.MarvinException;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@Controller
@RequestMapping("/rest")
public class MusicServices {
	private static SubscriptionServer subServer;
	public static final Integer SUBSCRIPTION_PORT = 4242;

	public MusicServices(){		
		startSubscriptionServer();
	}
	
	private void startSubscriptionServer(){
		if(subServer == null){
			subServer = new SubscriptionServer(SUBSCRIPTION_PORT);
			subServer.start();
			
			MarvinClient.startClient();
		}
	}
	
	/**
	 * Return a static message
	 * @return
	 */
	@RequestMapping(value = "/info")
	public @ResponseBody String getInfo() {
		return ServiceURIs.getServicesDescription();  
	}
	
	/**
	 * Return a list of connected clients
	 * @return
	 */
	@RequestMapping(value = ServiceURIs.LIST_CLIENTS)
	public @ResponseBody ClientList listClients() {
		LinkedList<Client> cDto = new LinkedList<Client>();
		for (ClientHandler c : subServer.getClients()) {
			Client client = new Client(c.getClientName());
			List<File> files = c.getPlayList();
			if(files != null){
				for (File file : files) {
					client.getPlayList().addItem(file.getAbsolutePath());
				}
			}
			cDto.add(client);
		}
		ClientList cList = new ClientList();
		cList.setClients(cDto);
		return cList;
	}
	
	@RequestMapping(value = ServiceURIs.PLAY_WEB_RADIO)
	@ResponseStatus(value = HttpStatus.OK)
	public void playWebradio(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName, @PathVariable(ServiceURIs.PARAM_PATH) String radioPath){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null){
			try {
				System.out.println("Try to stream: "+radioPath+" on client: "+clientName);
				String decodedPath = "";
		        try {
		        	decodedPath = java.net.URLDecoder.decode(radioPath, "ISO-8859-1");
		        	decodedPath += ".mp3";
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
		        System.out.println("Try to stream: "+decodedPath+" on client: "+clientName);
				cHandler.stream(new URI(decodedPath));
			} catch (IOException e) {
				e.printStackTrace();
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.PLAY_FILE, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void playFile(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName, @PathVariable(ServiceURIs.PARAM_PATH) String filePath, @PathVariable(ServiceURIs.PARAM_TYPE) String type){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null){
			try {
				String decodedPath = "";
		        try {
		        	decodedPath = java.net.URLDecoder.decode(filePath, "ISO-8859-1");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
		        System.out.println("Try to stream: "+decodedPath+" on client: "+clientName);
				cHandler.streamFile(new File(new URI(decodedPath)));
			} catch (IOException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (MarvinException e) {
				e.printStackTrace();
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	@RequestMapping(value = ServiceURIs.ADD_TO_PLAY_LIST, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void addToPlayList(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName, @PathVariable(ServiceURIs.PARAM_PATH) String path,  @PathVariable(ServiceURIs.PARAM_TYPE) String type){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null){
			try {
				String decodedPath = "";
		        try {
		        	decodedPath = java.net.URLDecoder.decode(path, "ISO-8859-1");
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				cHandler.getPlayList().add(new File(new URI(decodedPath)));
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.PLAY_LIST_PLAY, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void playPlayList(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null){
			try {
				cHandler.streamPlayList();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (MarvinException e) {
				e.printStackTrace();
			}
		}
	}

	@RequestMapping(value = ServiceURIs.STREAM_PAUSE, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void pauseStream(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getSrv().suspendStreaming();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.STREAM_STOP, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void stopStream(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getSrv().stopStreaming();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.STREAM_RESUME, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void resumeStream(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getSrv().resumeStreaming();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.STREAM_NEXT, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void streamNext(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getSrv().playNext();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.STREAM_PREVIOUS, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void streamPrevious(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getSrv().playPrevious();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping(value = ServiceURIs.PLAY_LIST_CLEAR, method = RequestMethod.PUT)
	@ResponseStatus(value = HttpStatus.OK)
	public void emptyPlaylist(@PathVariable(ServiceURIs.PARAM_CLIENT_NAME) String clientName){
		ClientHandler cHandler = searchClient(clientName);
		if(cHandler != null && cHandler.getSrv() != null){
			try {
				cHandler.getPlayList().clear();
			}catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}
	
	private ClientHandler searchClient(String clientName) {
		List<ClientHandler> clients = subServer.getClients(); 
		if(clients != null){
			for (ClientHandler clientHandler : clients) {
				if(clientHandler.getClientName() != null && clientHandler.getClientName().equals(clientName))
					return clientHandler;
			}
		}
		return null;
	}
}
